﻿using System;
using System.Collections.Generic;
using System.Management.Automation;
using BGShell.Components;
using BGShell.Drawing;

namespace BGShell.PowerShell.DataTips
{
    internal class PSObjectDataTip : TypeModelDataTip
    {
        public PSObjectDataTip(String name, Object value, Boolean valueIsCaughtException, Type type)
            : base(name, value, valueIsCaughtException, type)
        {
        }

        public PSObject ValueAsPSObject
        {
            get
            {
                if (Value != null)
                {
                    return PSObject.AsPSObject(Value);
                }

                return new PSObject();
            }
        }

        protected override TypeModelDataTip CreateArrayItem(string name, object value, Type elementType)
        {
            return new PSObjectDataTip(name, value, false, elementType);
        }

        protected override IEnumerable<DataTipItem> MemberSubItems()
        {
            foreach (var prop in ValueAsPSObject.Properties)
            {
                var icon = TypeModelIcon.Property;
                var overlay = GetOverlay(prop, ref icon);

                var exceptionThrown = false;

                var value = TryGetValue(prop, out exceptionThrown);
                var type = TryGetType(prop);

                yield return new PSObjectDataTip(prop.Name, value, exceptionThrown, type)
                {
                    Icon = icon,
                    IconOverlay = overlay,
                };
            }
        }

        protected override IEnumerable<DataTipItem> AppendSubItems()
        {
            var rawView = new PSObjectRawDataTip("PSBase", Value, false, ValueType)
            {
                Icon = TypeModelIcon.Field,
            };

            if (rawView.Subitems.Count > 0)
            {
                yield return rawView;
            }

            if (!typeof(PSObject).IsAssignableFrom(ValueType))
            {
                var staticMembers = new StaticMembersDataTip(ValueType);

                if (staticMembers.Subitems.Count > 0)
                {
                    yield return staticMembers;
                }
            }
        }

        private static TypeModelIconOverlay GetOverlay(PSPropertyInfo prop, ref TypeModelIcon icon)
        {
            switch (prop.MemberType)
            {
                case PSMemberTypes.AliasProperty:
                    icon = TypeModelIcon.Property;
                    return TypeModelIconOverlay.Alias;

                case PSMemberTypes.CodeProperty:
                    icon = TypeModelIcon.Property;
                    return TypeModelIconOverlay.Assembly;

                case PSMemberTypes.NoteProperty:
                    icon = TypeModelIcon.Field;
                    return TypeModelIconOverlay.None;

                case PSMemberTypes.ScriptProperty:
                    icon = TypeModelIcon.ScriptProperty;
                    return TypeModelIconOverlay.None;
            }

            icon = TypeModelIcon.Property;
            return TypeModelIconOverlay.None;
        }

        private static Object TryGetValue(PSPropertyInfo prop, out bool exceptionThrown)
        {
            try
            {
                exceptionThrown = false;
                return prop.Value;
            }
            catch (GetValueException exc)
            {
                exceptionThrown = true;
                return exc.InnerException;
            }
        }

        private static Type TryGetType(PSPropertyInfo prop)
        {
            return Type.GetType(prop.TypeNameOfValue, false);
        }
    }
}
